package com.payment.ctl;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * dongzhihua
 * 2022/10/22 23:21
 */
@Slf4j
@RestController
@RequestMapping("hystrix")
@DefaultProperties(defaultFallback = "fallback")
public class PaymentHystrixCtl {

    @RequestMapping("success")
    public String success() {
        return "success threadId=" + Thread.currentThread().getId();
    }

    @RequestMapping("timeout")
    @HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
    })
    public String timeout(@RequestParam(defaultValue = "1") Integer seconds) throws InterruptedException {
        log.info("call timeout");
        TimeUnit.SECONDS.sleep(seconds);
        return String.format("timeout=%s秒, threadId=%s", seconds, Thread.currentThread().getName());
    }

    public String timeOutHandler(@RequestParam(defaultValue = "1") Integer seconds) {
        log.info("fallback timeout");
        return String.format("fallback timeout=%s秒, thread=%s", seconds, Thread.currentThread().getName());
    }

    @RequestMapping("timeout1")
    @HystrixCommand(commandProperties = {
            // 超时降级，当超时，stop线程不再继续处理
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
    })
    public String timeout1(@RequestParam(defaultValue = "1") Integer seconds) throws InterruptedException {
        log.info("call timeout1");
        long end = TimeUnit.SECONDS.toMillis(seconds) + System.currentTimeMillis();
        while (System.currentTimeMillis() < end) {
            log.info("run ...");
            TimeUnit.MILLISECONDS.sleep(100);
        }
        log.info("call timeout end");
        return String.format("timeout1=%s秒, threadId=%s", seconds, Thread.currentThread().getName());
    }

    @RequestMapping("exception")
    @HystrixCommand
    public String exception(boolean exceptionExist) {
        log.info("call exception");
        Assert.isTrue(!exceptionExist, "发生异常");
        return String.format("exceptionExist=%s threadId=%s", exceptionExist, Thread.currentThread().getName());
    }

    public String fallback() {
        log.info("default fallback");
        return String.format("default fallback thread=%s", Thread.currentThread().getName());
    }

    @RequestMapping("breaker")
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),/* 是否开启断路器*/
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失败率达到多少后跳闸
    })
    public String breaker(Integer flag) {
        Assert.isTrue(flag > 0, "熔断");
        return "success";
    }
}
